package com.classes;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Map;
import java.util.TreeMap;

import org.json.simple.JSONArray;
import org.json.simple.JSONValue;

import com.mbbmap.app.dao.UserDao;
import com.mbbmap.app.home.SecUsersHome;
import com.mbbmap.app.manager.ConfigManager;
import com.mbbmap.app.manager.DBConnectionManager;
import com.mbbmap.security.dao.SecUserDao;
import com.mbbmap.util.Constants;

public class Notification {
	private TreeMap<String, GroupUser> users = new TreeMap<String, GroupUser>();
	private TreeMap<String, String> info;
	private String message;
	private int ntf_id;
	private Casemast c;
	
	public static String formatCreatedDate(String fmt, long created_dt){
		SimpleDateFormat df = new SimpleDateFormat(fmt);
		Date dt = new Date(created_dt);
		
		return df.format(dt);
	}
	
	public String getMessage() {
		return "[Notification] " + this.message; 
	}
	
	public boolean setUsers(String status_group, String strEMerchant) {
		JSONArray arr = (JSONArray) JSONValue.parse(status_group);
		
		if(arr != null) {
			String group_regex = "ug::";
			String user_regex = "uu::";
			
			for(int k = 0; k < arr.size(); k++) {
				String item = arr.get(k).toString();
				
				System.out.println("Item => " + item);
				
				if(item.startsWith(user_regex)) {
					
					String[] a = item.split(user_regex);
					String userId = a[1];
					
					UserDao userdao = SecUsersHome.getInstance().getUser(strEMerchant, userId);
					
					GroupUser u = new GroupUser();
					u.setUserId(userId);
					u.setInfo("name", userdao.getUserName());
					u.setInfo("email", userdao.getEmail());
					System.out.println("User ID => " + userId + ", Email => " + userdao.getEmail());
					if(!users.containsKey(userId)){
						users.put(userId, u);
					}
					
				} else if(item.startsWith(group_regex)) {
					
					String[] a = item.split(group_regex);
					String group_code = a[1];
					
					ArrayList<SecUserDao> userList = new ArrayList<SecUserDao>();
					if ((strEMerchant != null) && (!strEMerchant.equals(""))){
						userList = SecUsersHome.getInstance().findSecGroupUserList(strEMerchant, group_code);
					}
					
					for(SecUserDao s : userList){
						GroupUser u = new GroupUser();
						u.setUserId(s.getLogonId());
						u.setInfo("name", s.getUserName());
						u.setInfo("email", s.getEmail());
						
						if(!users.containsKey(s.getLogonId())){
							users.put(s.getLogonId(), u);
						}
					}
					
				} else {
					this.message = "Notification.java: getUsers :: Invalid STATUS GROUP / USER Role Code provided.";
					System.out.println(this.message);
					
					return false;
				}
			}
		}
		
		return true;
	}
	
	public Casemast getCasemast(){
		return this.c;
	}
	
	public int getNtfId(){
		return this.ntf_id;
	}
	
	public String getInfo(String key){
		if(this.info == null){
			return null;
		}
		
		if(this.info.containsKey(key)){
			return this.info.get(key);
		}
		
		return null;
	}
	
	public void setCasemast( Casemast value ){
		this.c = value;
	}
	
	public void setNtfId( int value ){
		this.ntf_id = value;
	}
	
	public void setInfo( String key, String value ){
		if(this.info == null){
			this.info = new TreeMap<String, String>();
		}
		
		this.info.put(key, value);
	}
	
	public boolean run(String channel, String loginUser) {
		if(channel.equals("dashboard")) {
			return dashboard(loginUser);
		} else if(channel.equals("email")) {
			return email(loginUser, channel);
		}
		
		return false;
	}
	
	public boolean dashboard(String loginUser) {
		String action = this.getInfo("action");
		String[] template = getTemplate(action, "dashboard");
		long case_id = this.getCasemast().getId();
		long hist_id = Long.parseLong(this.getInfo("hist_id"));
		
		if(template == null) {
			return false;
		}

		boolean ok = true;
		
		for(Map.Entry<String, GroupUser> u : this.users.entrySet()) {
			String userId = u.getKey();
			GroupUser user = u.getValue();
			String name = user.getInfo("name");
			
			String[] keyword = {"#user_id#", "#ref_no#"};
			String[] replace = {name, this.getCasemast().getReferenceNo()};
			
			String content = generateContent(template[1], keyword, replace);
			
			ok = createNotification(userId, case_id, action, content, loginUser, hist_id);
			if(ok == false) {
				return false;
			}
		}
		
		return true;

	}
	
	public boolean email(String loginUser, String channel) {
		String action = this.getInfo("action");
		String note = this.getInfo("note");
		String template[] = getTemplate(action, channel);
		if(template == null) {
			return false;
		}

		boolean ok = true;
		
		for(Map.Entry<String, GroupUser> u : this.users.entrySet()) {
			String userId = u.getKey();
			GroupUser user = u.getValue();
			
			String name = user.getInfo("name");
			String email = user.getInfo("email");
			if(email == null || email.trim().equals("")){
				continue;
			}
			
			String[] keyword = {"#user_id#", "#status_note#" ,"#ref_no#"};
			String[] replace = {name, note, this.getCasemast().getReferenceNo()};
			String subject = template[0];
			String content = generateContent(template[1], keyword, replace);

			ok = createNotificationQueue(email, action, subject, content, loginUser);
			if(ok == false) {
				return false;
			}
		}
		
		return true;

	}
	
	public boolean emailVendorPOS(String loginUser, String email, String name, String serialNo, String channel) {

		String template[] = getTemplate("", channel);
		if(template == null) {
			return false;
		}

		boolean ok = true;

		if(email == null || email.trim().equals("")){
			return false;
		}
		
		String[] keyword = {"#vendor_name#", "#ser_no#"};
		String[] replace = {name, serialNo};
		
		String subject = template[0];
		String content = generateContent(template[1], keyword, replace);

		ok = createNotificationQueue(email, "", subject, content, loginUser);
		if(ok == false) {
			return false;
		}

		return true;

	}
	
	public String[] getTemplate(String type, String channel) {	
		try {
	        int TIMEOUT = 10000; //DB connection timeout if unable to get connection in less than 10 seconds
	        String connectionPool = ConfigManager.getInstance().getConnectionPool();
	        DBConnectionManager connMgr = DBConnectionManager.getInstance();
	        try { TIMEOUT = Integer.parseInt(ConfigManager.getInstance().get(Constants.DB_WAIT_TIME)); } catch (Exception e) {}
	        Connection conn = connMgr.getConnection(connectionPool, TIMEOUT);
			
			try {
				String sql = "select nt_template, ntftemplate.* from ntftemplate where nt_channel = ?";
				
				PreparedStatement statement = conn.prepareStatement(sql);
				
				try {
					statement.setString(1, channel);
					
					ResultSet resultSet = statement.executeQuery();
					String[] template = new String[2];
					
					try {
						if(resultSet.next()){
							template[0] = resultSet.getString("nt_subject") == null ? "" : resultSet.getString("nt_subject");
							template[1] = resultSet.getString("nt_template") == null ? "" : resultSet.getString("nt_template");
							
							return template;
						}
						else {
							this.message = "No Notification Template found. ";
							System.out.println("Notification.java: getTemplate :: " + this.message + " NT_CHANNEL : " + channel);
							return null;
						}
					} finally {
						resultSet.close();
					}
				} finally {
					statement.close();
				}
				
			} finally {
				connMgr.freeConnection(connectionPool, conn);
			}
			
		} catch (Exception e){
			this.message = "getTemplate() " + e.getMessage();
			return null;
		}
	}
	
	public String generateContent(String template, String[] keyword, String[] replace) {
		String content = template; 
		
		for(int i = 0; i < keyword.length; i++) {
			content = content.replace(keyword[i], replace[i]);
		}
		
		return content;
	}
	
	public boolean updateNotificationStatus(long notification_id, String status, String userId){
		try {
	        int TIMEOUT = 10000; //DB connection timeout if unable to get connection in less than 10 seconds
	        String connectionPool = ConfigManager.getInstance().getConnectionPool();
	        DBConnectionManager connMgr = DBConnectionManager.getInstance();
	        try { TIMEOUT = Integer.parseInt(ConfigManager.getInstance().get(Constants.DB_WAIT_TIME)); } catch (Exception e) {}
	        Connection conn = connMgr.getConnection(connectionPool, TIMEOUT);
			
			try {
				String sql = "update notification set n_status = ?, "
						+ "	n_modified_date = sysdate, "
						+ "	n_modified_by = ? "
						+ "where n_id = ?";
				
				PreparedStatement statement = conn.prepareStatement(sql);
				
				try {
					statement.setString(1, status);
					statement.setString(2, userId);
					statement.setLong(3, notification_id);
					
					statement.execute();
					
				} finally {
					statement.close();
				}
				
			} finally {
				connMgr.freeConnection(connectionPool, conn);
			}
			
			return true;
			
		} catch (Exception e){
			this.message = "updateNotificationStatus() " + e.getMessage();
			return false;
		}
	}
	
	public boolean createNotification(String userId, long case_id, String type, String content, String loginUser, long hist_id) {	
		try {
	        int TIMEOUT = 10000; //DB connection timeout if unable to get connection in less than 10 seconds
	        String connectionPool = ConfigManager.getInstance().getConnectionPool();
	        DBConnectionManager connMgr = DBConnectionManager.getInstance();
	        try { TIMEOUT = Integer.parseInt(ConfigManager.getInstance().get(Constants.DB_WAIT_TIME)); } catch (Exception e) {}
	        Connection conn = connMgr.getConnection(connectionPool, TIMEOUT);
			
			try {
				String sql = "insert into notification (n_user_id, n_case_id, n_type, n_content, n_hist_id, "
						+ "	n_created_date, n_created_by, n_modified_date, n_modified_by) "
						+ "values (?, ?, ?, ?, ?, sysdate, ?, sysdate, ?)";
				
				PreparedStatement statement = conn.prepareStatement(sql);
				
				try {
					statement.setString(1, userId);
					statement.setLong(2, case_id);
					statement.setString(3, type);
					statement.setString(4, content);
					statement.setLong(5, hist_id);
					statement.setString(6, loginUser);
					statement.setString(7, loginUser);
					
					statement.execute();
				} finally {
					statement.close();
				}
				
			} finally {
				connMgr.freeConnection(connectionPool, conn);
			}
			
			return true;
			
		} catch (Exception e){
			this.message = "createNotification() " + e.getMessage();
			return false;
		}
	}
	
	public boolean createNotificationQueue(String email, String type, String subject, String content, String loginUser) {	
		try {
	        int TIMEOUT = 10000; //DB connection timeout if unable to get connection in less than 10 seconds
	        String connectionPool = ConfigManager.getInstance().getConnectionPool();
	        DBConnectionManager connMgr = DBConnectionManager.getInstance();
	        try { TIMEOUT = Integer.parseInt(ConfigManager.getInstance().get(Constants.DB_WAIT_TIME)); } catch (Exception e) {}
	        Connection conn = connMgr.getConnection(connectionPool, TIMEOUT);
			
			try {
				String sql = "insert into NTFQueue(nq_to, nq_type, nq_subject, nq_body, "
						+ "nq_created_date, nq_created_by) "
						+ "values (?, ?, ?, ?, sysdate, ?)";
				
				PreparedStatement statement = conn.prepareStatement(sql);
				
				try {
					statement.setString(1, email);
					statement.setString(2, type);
					statement.setString(3, subject);
					statement.setString(4, content);
					statement.setString(5, loginUser);
					
					statement.execute();
				} finally {
					statement.close();
				}
				
			} finally {
				connMgr.freeConnection(connectionPool, conn);
			}
			
			return true;
			
		} catch (Exception e){
			this.message = "createNotificationQueue() " + e.getMessage();
			return false;
		}
	}
}